package com.ym521.logdog

import android.content.Context
import androidx.annotation.MainThread
import com.ym521.logdog.core.*
import com.ym521.logdog.crash.CrashExceptionCallBack
import com.ym521.logdog.crash.CrashHandlerEngine
import com.ym521.logdog.engine.LogDogEngine
import com.ym521.logdog.utils.CacheUtil

/**
 * @author YM
 * @E-mail 2435970206@qq
 * @QQ 2435970206
 * logDog （日志狗）
 * 对外提供功能需求
 */
object LogDog {
    //对外提供的配置对象 可以进行修改
    private var logEngine: ILogDogEngine? = null

    //-----------------------------------------Log.debug()------------------------------------//
    @JvmStatic
    fun <T> debug(obj: T?) {
        debug(LogDogConfig.TAG, obj ?: "null")
    }


    @JvmStatic
    fun <T> debug(tag: String, obj: T?) {
        logEngine?.debug(tag, obj ?: "null")
    }

    @JvmStatic
    fun debugf(tag: String, stringFormat: String, vararg objs: Any) {
        logEngine?.debug(tag, stringFormat, *objs)
    }


    //-----------------------------------------Log.info()-------------------------------------//
    @JvmStatic
    fun <T> info(obj: T?) {
        info(LogDogConfig.TAG, obj ?: "")
    }

    @JvmStatic
    fun <T> info(tag: String, obj: T?) {
        logEngine?.info(tag, obj ?: "null")
    }

    @JvmStatic
    fun infof(tag: String, stringFormat: String, vararg objs: Any) {
        logEngine?.info(tag, stringFormat, *objs)
    }


    //-----------------------------------------Log.warn()-------------------------------------//
    @JvmStatic
    fun <T> warn(obj: T?) {
        warn(LogDogConfig.TAG, obj ?: "null")
    }

    @JvmStatic
    fun <T> warn(tag: String, obj: T?) {
        logEngine?.warn(tag, obj ?: "null")
    }

    @JvmStatic
    fun warnf(tag: String, stringFormat: String, vararg objs: Any) {
        logEngine?.warn(tag, stringFormat, *objs)
    }

    //-----------------------------------------Log.error()-------------------------------------//
    @JvmStatic
    fun <T> error(obj: T?) {
        error(LogDogConfig.TAG, obj ?: "null")
    }

    @JvmStatic
    fun <T> error(tag: String, obj: T?) {
        logEngine?.error(tag, obj ?: "null")
    }

    @JvmStatic
    fun errorf(tag: String, stringFormat: String, vararg objs: Any) {
        logEngine?.error(tag, stringFormat, *objs)
    }

    //-----------------------------------------Log.custom()-------------------------------------//
    /**
     * @param printer 打印开关
     * @param write 写文件开关
     */
    @JvmStatic
    fun <T> custom(
        printer: Boolean, write: Boolean, priority: LogPriority, tag: String, msg: T?
    ) {
        logEngine?.custom(priority, tag, msg ?: "null", printer, write)
    }

    /**
     * @param printer 打印开关
     * @param write 写文件开关
     * 其他一律采用VERBOSE 日志级别打印！
     */
    @JvmStatic
    fun customf(
        printer: Boolean,
        write: Boolean,
        priority: LogPriority,
        tag: String,
        stringFormat: String,
        vararg objs: Any
    ) {
        logEngine?.custom(printer, write, priority, tag, stringFormat, *objs)
    }

    /**
     * 日志文件 分享
     * 可以将日志文件分享给其他应用便于开发人员定位问题
     */
    @MainThread
    @JvmStatic
    fun logFileShare(mContext: Context) {
        logFileShare(mContext, LogFileType.LOG_FILE)
    }

    /**
     * 日志文件 分享
     * 由于新增 Crash 日志文件 所以新增了 日志文件类型
     */
    @MainThread
    @JvmStatic
    fun logFileShare(mContext: Context, fileType: LogFileType) {
        logEngine?.shareLogFile(mContext, fileType)
    }


    @JvmStatic
    val builder: Builder
        get() = _builder!!

    //对外提供动态修改logDog的配置
    private var _builder: Builder? = null
    /**
     * LogDog 构建
     * 提供对LogDog的配置
     */
    class Builder {
        /**
         * 是否打印线程信息
         */
        fun logShowThreadInfoEnable(enabled: Boolean): Builder {
            LogDogConfig.isShowThreadInfo = enabled
            return this
        }

        /**
         * @param enabled 是否打印方法信息
         * @param methodCount 打印方法的个数 如果小于1 为1，大于10 为10
         */
        fun logShowMethodEnable(
            enabled: Boolean, @androidx.annotation.IntRange(
                from = 0, to = 10
            ) methodCount: Int = 2
        ): Builder {
            LogDogConfig.isShowMethod = enabled
            LogDogConfig.showMethodCount = methodCount
            return this
        }


        /**
         * 是否将日志写入日志文件中
         * 日志文件以当天日期为单位生成日志文件
         */
        fun logWriteFileEnable(enabled: Boolean): Builder {
            LogDogConfig.isWriteLogFileEnable = enabled
            return this
        }

        /**
         * 是否启动AES 加密
         * 如果启动加密 但未配置key下,
         * 将使用默认秘钥"0000000000000000"
         * AES 可能比较耗时 如果安全考虑 可以开启编码混淆
         */
        fun logFileAESEnable(enabled: Boolean, key: String = "0000000000000000"): Builder {
            LogDogConfig.isLogFileAES = enabled
            if (key.toByteArray(Charsets.UTF_8).size == 16) {
                LogDogConfig.logFileAES_key = key
            } else {
                LogDogConfig.isLogFileAES = false
                LogDogConfig.logFileAES_key = ""
            }
            return this
        }

        /**
         * 是否将日志文件输出到外部私有空间
         */
        fun logFileExtEnable(enabled: Boolean): Builder {
            LogDogConfig.logFileShow = enabled
            return this
        }

        /**
         * 自定义 设置，没有自行填写的TAG的统一缺省TAG
         */
        fun defaultTAG(tag: String): Builder {
            if (tag.isNotBlank()) {
                LogDogConfig.TAG = tag
            }
            return this
        }

        /**
         * 打印日志过滤日志级别，默认全部打印
         * 日志过滤是过滤掉你添加的日志级别，不想打印的级别日志需要你添加对应的日志级别
         */
        fun logPrintFilter(vararg logPriority: LogPriority): Builder {
            var priority = 0
            logPriority.forEach {
                priority = priority or it.priority
            }
            LogDogConfig.logFilter = priority
            return this
        }

        /**
         * 写入日志文件的过滤日志级别，默认全部打印
         * 日志过滤是过滤掉你添加的日志级别，不想打印的级别日志需要你添加对应的日志级别
         */
        fun logWriteFilter(vararg logPriority: LogPriority): Builder {
            var priority = 0
            logPriority.forEach {
                priority = priority or it.priority
            }
            LogDogConfig.logWriteFilter = priority
            return this
        }

        /**
         * 自定义方法/函数栈的打印零点的额外补充调整
         * 默认 0
         * 限制在 -3 到 5之间的额外补充调整
         * 仅对开启了打印日志方法栈下(logShowMethodEnable:true) 有效
         */
        fun extraOffset(@androidx.annotation.IntRange(from = -3, to = 5) offset: Int): Builder {
            LogDogConfig.extraOffset = offset
            return this
        }

        /**
         * 格式化换行
         * @isWrap true 开启，false 关闭， 默认 false
         * 如果便于实时查看日志 建议开启 方便 日志观看，
         * 如果对日志格式要求较高，怕换行造成日志不严谨，建议关闭或者不设置
         */
        fun wrapFormat(isWrap: Boolean): Builder {
            LogDogConfig.isWrap = isWrap
            return this
        }

        /**
         * Crash处理
         * @param enabled true 开启，false 关闭， 默认 false
         * @param callback 开发人员可以自定义 crash 处理
         * 如果开发人员 不想实现自定义处理，默认处理是2秒后将关闭APP进程；
         * 可以不实现自定义处理。
         *
         * 特别强调：@callback 是在子线程中 回调
         */
        fun crashHandlerEnable(enabled: Boolean, callback: CrashExceptionCallBack?): Builder {
            if (enabled) {
                val crashHandler = CrashHandlerEngine.build()
                callback?.let {
                    crashHandler.setCustomHandler(it)
                }
                logEngine?.let {
                    crashHandler.onCrashHandler(it)
                }
            }
            return this
        }

        fun crashHandlerEnable(enabled: Boolean): Builder {
            crashHandlerEnable(enabled, null)
            return this
        }

        /**
         * 编码混淆 默认不开启
         * 编码混淆只针对 log文件编码混淆
         * 如果开启 不能在运行中和同一天（同一个日志文件）内发生更改编码混淆开关， 不然会造成 log文件 无法正确解密
         */
        fun encodingConfusion(enabled: Boolean): Builder {
            LogDogConfig.encoding = enabled
            return this
        }

        /**
         * 日志文件的分割大小 默认10 MB
         * 仅对开启了写入日志文件下(logWriteLogFileEnable:true) 有效
         * @param size  分割日志文件的最大值 范围1MB ~ 200MB， 单位：MB
         */
        fun logFileSize(@androidx.annotation.IntRange(from = 1, to = 200) size: Int): Builder {
            if (size < 0) return this
            LogDogConfig.logFileSize = size
            return this
        }

        /**
         * 是否开启对新版本的LogCat支持
         */
        fun enabledNewLogCat(enabled: Boolean = true): Builder {
            LogDogConfig.isNewLogCat = enabled
            return this
        }

        /**
         * 初始化 LogDog日志 框架
         */
        @MainThread
        fun install(mContext: Context, jsonEngine: IJsonEngine) {
            if (_builder == null) {
                CacheUtil.initCache(mContext)
                logEngine = LogDogEngine.build(mContext, jsonEngine)
                _builder = Builder()
            }
        }
    }
}